@@ -0,0 +1,100 @@ |
||
1 |
+module Agents |
|
2 |
+ class StubhubAgent < Agent |
|
3 |
+ cannot_receive_events! |
|
4 |
+ |
|
5 |
+ description <<-MD |
|
6 |
+ This StubHubAgent creates an event for a given StubHub Event. It can be used to track how many tickets are available for the event and the minimum and maximum price. All that is required is that you paste in the url from the actual event, e.g. http://www.stubhub.com/outside-lands-music-festival-tickets/outside-lands-music-festival-3-day-pass-san-francisco-golden-gate-park-polo-fields-8-8-2014-9020701/ |
|
7 |
+ MD |
|
8 |
+ |
|
9 |
+ event_description <<-MD |
|
10 |
+ Events looks like this: |
|
11 |
+ { |
|
12 |
+ "url": "http://stubhub.com/valid-event-url" |
|
13 |
+ "name": "Event Name" |
|
14 |
+ "date": "2014-08-01" |
|
15 |
+ "max_price": "999.99" |
|
16 |
+ "min_price": "100.99" |
|
17 |
+ "total_postings": "50" |
|
18 |
+ "total_tickets": "150" |
|
19 |
+ "venue_name": "Venue Name" |
|
20 |
+ } |
|
21 |
+ MD |
|
22 |
+ |
|
23 |
+ default_schedule "every_1d" |
|
24 |
+ |
|
25 |
+ def working? |
|
26 |
+ event_created_within?(1) && !recent_error_logs? |
|
27 |
+ end |
|
28 |
+ |
|
29 |
+ def default_options |
|
30 |
+ { 'url' => 'http://stubhub.com/enter-your-event-here' } |
|
31 |
+ end |
|
32 |
+ |
|
33 |
+ def validate_options |
|
34 |
+ errors.add(:base, 'url is required') unless options['url'].present? |
|
35 |
+ end |
|
36 |
+ |
|
37 |
+ def url |
|
38 |
+ options['url'] |
|
39 |
+ end |
|
40 |
+ |
|
41 |
+ def check |
|
42 |
+ create_event :payload => fetch_stubhub_data(url) |
|
43 |
+ end |
|
44 |
+ |
|
45 |
+ def fetch_stubhub_data(url) |
|
46 |
+ StubhubFetcher.call(url) |
|
47 |
+ end |
|
48 |
+ |
|
49 |
+ class StubhubFetcher |
|
50 |
+ |
|
51 |
+ def self.call(url) |
|
52 |
+ new(url).fields |
|
53 |
+ end |
|
54 |
+ |
|
55 |
+ def initialize(url) |
|
56 |
+ @url = url |
|
57 |
+ end |
|
58 |
+ |
|
59 |
+ def event_id |
|
60 |
+ /(\d*)\/{0,1}\z/.match(url)[1] |
|
61 |
+ end |
|
62 |
+ |
|
63 |
+ def base_url |
|
64 |
+ 'http://www.stubhub.com/listingCatalog/select/?q=' |
|
65 |
+ end |
|
66 |
+ |
|
67 |
+ def build_url |
|
68 |
+ base_url + "%2B+stubhubDocumentType%3Aevent%0D%0A%2B+event_id%3A#{event_id}%0D%0A&start=0&rows=10&wt=json" |
|
69 |
+ end |
|
70 |
+ |
|
71 |
+ def response |
|
72 |
+ uri = URI(build_url) |
|
73 |
+ Net::HTTP.get(uri) |
|
74 |
+ end |
|
75 |
+ |
|
76 |
+ def parse_response |
|
77 |
+ JSON.parse(response) |
|
78 |
+ end |
|
79 |
+ |
|
80 |
+ def fields |
|
81 |
+ stubhub_fields = parse_response['response']['docs'][0] |
|
82 |
+ { |
|
83 |
+ 'url' => url, |
|
84 |
+ 'name' => stubhub_fields['seo_description_en_US'], |
|
85 |
+ 'date' => stubhub_fields['event_date_local'], |
|
86 |
+ 'max_price' => stubhub_fields['maxPrice'].to_s, |
|
87 |
+ 'min_price' => stubhub_fields['minPrice'].to_s, |
|
88 |
+ 'total_postings' => stubhub_fields['totalPostings'].to_s, |
|
89 |
+ 'total_tickets' => stubhub_fields['totalTickets'].to_i.to_s, |
|
90 |
+ 'venue_name' => stubhub_fields['venue_name'] |
|
91 |
+ } |
|
92 |
+ end |
|
93 |
+ |
|
94 |
+ private |
|
95 |
+ |
|
96 |
+ attr_reader :url |
|
97 |
+ |
|
98 |
+ end |
|
99 |
+ end |
|
100 |
+end |
@@ -0,0 +1,17 @@ |
||
1 |
+{ |
|
2 |
+ "response":{ |
|
3 |
+ "docs":[ |
|
4 |
+ { |
|
5 |
+ "url": "http://www.stubhub.com/event/name-1-1-2014-12345", |
|
6 |
+ "seo_description_en_US": "name", |
|
7 |
+ "event_date_local": "2014-01-01", |
|
8 |
+ "maxPrice": "100", |
|
9 |
+ "minPrice": "50", |
|
10 |
+ "totalPostings": "100", |
|
11 |
+ "totalTickets": "200", |
|
12 |
+ "venue_name": "Venue Name" |
|
13 |
+ } |
|
14 |
+ ] |
|
15 |
+ } |
|
16 |
+} |
|
17 |
+ |
@@ -0,0 +1,67 @@ |
||
1 |
+require 'spec_helper' |
|
2 |
+ |
|
3 |
+describe Agents::StubhubAgent do |
|
4 |
+ |
|
5 |
+ let(:name) { 'Agent Name' } |
|
6 |
+ let(:url) { 'http://www.stubhub.com/event/name-1-1-2014-12345' } |
|
7 |
+ let(:parsed_body) { JSON.parse(body)['response']['docs'][0] } |
|
8 |
+ let(:valid_params) { { 'url' => parsed_body['url'] } } |
|
9 |
+ let(:body) { File.read(Rails.root.join('spec/data_fixtures/stubhub_data.json')) } |
|
10 |
+ let(:stubhub_event_id) { 12345 } |
|
11 |
+ let(:response_payload) { { |
|
12 |
+ 'url' => url, |
|
13 |
+ 'name' => parsed_body['seo_description_en_US'], |
|
14 |
+ 'date' => parsed_body['event_date_local'], |
|
15 |
+ 'max_price' => parsed_body['maxPrice'], |
|
16 |
+ 'min_price' => parsed_body['minPrice'], |
|
17 |
+ 'total_postings' => parsed_body['totalPostings'], |
|
18 |
+ 'total_tickets' => parsed_body['totalTickets'], |
|
19 |
+ 'venue_name' => parsed_body['venue_name'] |
|
20 |
+ } } |
|
21 |
+ |
|
22 |
+ before do |
|
23 |
+ stub_request(:get, "http://www.stubhub.com/listingCatalog/select/?q=%2B%20stubhubDocumentType:event%0D%0A%2B%20event_id:#{stubhub_event_id}%0D%0A&rows=10&start=0&wt=json"). |
|
24 |
+ to_return(:status => 200, :body => body, :headers => {}) |
|
25 |
+ |
|
26 |
+ @stubhub_agent = described_class.new(name: name, options: valid_params) |
|
27 |
+ @stubhub_agent.user = users(:jane) |
|
28 |
+ @stubhub_agent.save! |
|
29 |
+ end |
|
30 |
+ |
|
31 |
+ |
|
32 |
+ describe "#check" do |
|
33 |
+ |
|
34 |
+ it 'should create an event' do |
|
35 |
+ expect { @stubhub_agent.check }.to change { Event.count }.by(1) |
|
36 |
+ end |
|
37 |
+ |
|
38 |
+ it 'should properly parse the response' do |
|
39 |
+ event = @stubhub_agent.check |
|
40 |
+ event.payload.should == response_payload |
|
41 |
+ end |
|
42 |
+ end |
|
43 |
+ |
|
44 |
+ describe "validations" do |
|
45 |
+ before do |
|
46 |
+ @stubhub_agent.should be_valid |
|
47 |
+ end |
|
48 |
+ |
|
49 |
+ it "should require a url" do |
|
50 |
+ @stubhub_agent.options['url'] = nil |
|
51 |
+ @stubhub_agent.should_not be_valid |
|
52 |
+ end |
|
53 |
+ |
|
54 |
+ end |
|
55 |
+ |
|
56 |
+ describe "#working?" do |
|
57 |
+ it "checks if events have been received within the expected receive period" do |
|
58 |
+ @stubhub_agent.should_not be_working |
|
59 |
+ |
|
60 |
+ Agents::StubhubAgent.async_check @stubhub_agent.id |
|
61 |
+ @stubhub_agent.reload.should be_working |
|
62 |
+ two_days_from_now = 2.days.from_now |
|
63 |
+ stub(Time).now { two_days_from_now } |
|
64 |
+ @stubhub_agent.reload.should_not be_working |
|
65 |
+ end |
|
66 |
+ end |
|
67 |
+end |